const EventInit = require("events")
const MuteStream = require("mute-stream")
const readLine = require("readline");
const {fromEvent} = require("rxjs")
const ansiEscapes = require("ansi-escapes");
const option =     {
    type: "list",// rawlist 与list唯一区别为下方有一个Answer提示
    name: "choice",// 必传  作为键值对中key出现
    message: "your choice: ",
    choices: [
      {
        value: "value1",
        name: "name1"
      },
      {
        value: "value2",
        name: "name2"
      },
      {
        value: "value3",
        name: "name3"
      }
    ]
};

function prompt(option) {
    return new Promise((res, rej) => {
        try {
            const list = new List(option)
            list.render();
            list.on("exit", (answers) => {
                res(answers);
            })
        } catch (e) {
            rej(e);
        }
    })
}

class List extends EventInit {
    constructor(option) {
        super()
        this.name = option.name;
        this.message = option.message;
        this.choices = option.choices
        this.input = process.stdin;
        const ms = new MuteStream();
        ms.pipe(process.stdout);
        this.output = ms;
        this.rl = readLine.createInterface({
            input: this.input,
            output: this.output 
        });
        this.selected = 0;
        this.height = 0;
        this.keypress = fromEvent(this.rl.input, "keypress").forEach(this.onKeypress)
        this.haveSelected = false;// 是否已经选择完毕
    }
    onKeypress = (keyMap) => {
        const key = keyMap[1]
        if(key.name === "down") {
            this.selected++;
            if(this.selected > this.choices.length - 1) {
                this.selected = 0;
            }
            this.render();
        }else if(key.name === "up") {
            this.selected--;
            if(this.selected < 0) {
                this.selected = this.choices.length - 1;
            }
            this.render();
        }else if(key.name === "return") {
            this.haveSelected = true;
            this.render()
            this.close()
            this.emit("exit", this.choices[this.selected]);
        }
    }
    render() {
        this.output.unmute();// 接触output的禁用
        this.clear();
        this.output.write(this.getContent())
        this.output.mute();// 禁止用户在界面输入文字
    }
    getContent = () => {
        if(!this.haveSelected) {
            let title = "\x1B[32m?\x1B[39m \x1B[1m" + this.message + "\x1B[22m\x1B[0m\x1B[2m(use arrow keys)\x1B[22m\n";
            this.choices.forEach((choice, index) => {
                if(index === this.selected) {
                    if(index === this.choices.length - 1) {
                        title += `\x1B[36m> ${choice.name} \x1B[39m`;
                    }else {
                        title +=  `\x1B[36m> ${choice.name}\n\x1B[39m`;
                    }
                } else {
                    if(index === this.choices.length - 1) {
                        title += `  ${choice.name}`;
                    }else {
                        title += `  ${choice.name}\n`;
                    }
                }
            })
            this.height = this.choices.length + 1;
            return title;
        }else {
            // 结束后的逻辑
            const name = this.choices[this.selected].name;
            let title = "\x1B[32m?\x1B[39m \x1B[1m" + this.message + "\x1B[22m\x1B[0m\x1B[36m"+ name +"\x1B[39m\x1B[0m \n";
            return title;
        }
    }
    clear(){
         const emptyLenth = ansiEscapes.eraseLines(this.height);
         this.output.write(emptyLenth)
    }
    close() {
        this.output.unmute();// 禁止获取输入
        this.rl.output.end();
        this.rl.pause();
        this.rl.close();
    }
}

prompt(option).then(res => console.log(res));
